﻿#include"ThreadCache.hpp"
#include"CentralCache.hpp"
void* ThreadCache::Allocate(size_t size) {
	assert(size <= MAX_BYTES);
	size_t alignSize = SizeClass::RoundUp(size);//算出对齐大小
	size_t index = SizeClass::Index(size);//算出桶号
	if (!_freeLists[index].Empty()) return _freeLists[index].Pop();
	else return FetchFromCentralCache(index, alignSize);
}

void ThreadCache::Deallocate(void* ptr, size_t size) {
	assert(ptr&& size <= MAX_BYTES);
	// 找对映射的自由链表桶，对象插入进入
	size_t index = SizeClass::Index(size);
	_freeLists[index].Push(ptr);
	//当链表长度大于一次批量申请的内存时就开始还一段list给central cache
	if(_freeLists[index].GetSize()>= _freeLists[index].GetMaxsize()) 
		ListTooLong(_freeLists[index], size);
}

// 从中心缓存获取对象  问题在于我一次要获取多少？
void* ThreadCache::FetchFromCentralCache(size_t index, size_t size) {
	// 慢开始反馈调节算法
	// 1、最开始不会一次向central cache一次批量要太多，因为要太多了可能用不完
	// 2、如果你不要这个size大小内存需求，那么batchNum（批量化的块数）就会不断增长，直到上限
	// 3、size越大，一次向central cache要的batchNum就越小
	// 4、size越小，一次向central cache要的batchNum就越大
	size_t batchNum = (std::min)(_freeLists[index].GetMaxsize(), SizeClass::NumMoveSize(size));
	if (batchNum == _freeLists[index].GetMaxsize()) _freeLists[index].GetMaxsize() += 1;
	//接下来要做先从CentralCache获取我们想要的一个自由链表的范围 start end（//输入输出型参数） batchNum(个数) size(每个内存块的大小)
	void* start = nullptr;
	void* end = nullptr; 
	size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(start, end, batchNum, size);
	assert(actualNum>0);
	if (actualNum > 1)   _freeLists[index].PushRange(NextObj(start), end, actualNum-1);//将除了第一块之外的全都接到自由链表上
	return start;//返回第一块
}

// 释放对象时，链表过⻓时，回收内存回到中心缓存 
void ThreadCache::ListTooLong(FreeList& list, size_t size) {
	void* start = nullptr;
	void* end = nullptr;
	//先把GetMaxsize()块给取出来
	list.PopRange(start, end, list.GetMaxsize());
	//然后把这些块还给Central Cache 
	CentralCache::GetInstance()->ReleaseListToSpans(start,size);//不需要传end  因为最后肯定走到nullptr
}